﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using AppConfig;
using ApplicationConfiguration;

namespace Logging
{
    public class SimpleLogger
    {
        private static IDictionary<string, SimpleLogger> loggers;
        private static IDictionary<string, SimpleLoggerLevel> loggerLevels = null;

        public static SimpleLogger getLogger(Type type, params SimpleLoggerAppender[] appenders)
        {
            if (loggers == null)
            {
                loggers = new Dictionary<string, SimpleLogger>();
            }
            if (loggerLevels == null)
            {
                loggerLevels = new Dictionary<string, SimpleLoggerLevel>();
                IDictionary<string, string> textLoggerLevels = AppConfiguration.getInstance().getProperties("Logging");
                foreach (KeyValuePair<string, string> textLoggerLevel in textLoggerLevels)
                    loggerLevels.Add(textLoggerLevel.Key, (SimpleLoggerLevel) Enum.Parse(typeof(SimpleLoggerLevel), textLoggerLevel.Value));
            }
            SimpleLogger logger = null;
            try
            {
                logger = loggers.Single(l => l.Key.Equals(type.FullName)).Value;
            }
            catch (Exception)
            {
                logger = new SimpleLogger(type.FullName);
                int matchLength = -1;
                SimpleLoggerLevel? level = null;
                foreach (KeyValuePair<string, SimpleLoggerLevel> loggerLevel in loggerLevels)
                {
                    if (logger.Name.StartsWith(loggerLevel.Key) && (loggerLevel.Key.Length > matchLength))
                    {
                        matchLength = loggerLevel.Key.Length;
                        level = loggerLevel.Value;
                    }
                }
                logger.Level = level;
                if (appenders.Length == 0)
                    appenders = new SimpleLoggerAppender[] { new SimpleLoggerConsoleAppender(SimpleLoggerFormatter.getFormatter(SimpleLoggerFormatter.DEFAULT_FORMAT_STRING)) };
            }
            foreach (SimpleLoggerAppender appender in appenders)
                logger.AddAppender(appender);
            loggers.Add(logger.Name, logger);
            return logger;
        }

        private string name;
        private SimpleLoggerLevel? level;
        private ICollection<SimpleLoggerAppender> appenders;
        private int flushInterval;

        private int flushCount;

        private SimpleLogger(string name)
        {
            this.name = name;
            level = null;
            appenders = new List<SimpleLoggerAppender>();
            flushInterval = 1;
            flushCount = 0;
        }

        public string Name
        {
            get
            {
                return name;
            }
        }

        public SimpleLoggerLevel? Level
        {
            get
            {
                return level;
            }
            set
            {
                level = value;
            }
        }

        public void AddAppender(SimpleLoggerAppender appender)
        {
            appenders.Add(appender);
        }

        public void RemoveAppender(SimpleLoggerAppender appender)
        {
            appenders.Remove(appender);
        }

        public int FlushInterval
        {
            get
            {
                return flushInterval;
            }
            set
            {
                flushInterval = value;
            }
        }

        public void trace(string message)
        {
            log(SimpleLoggerLevel.TRACE, message);
        }

        public void debug(string message)
        {
            log(SimpleLoggerLevel.DEBUG, message);
        }

        public void info(string message)
        {
            log(SimpleLoggerLevel.INFO, message);
        }

        public void warning(string message)
        {
            log(SimpleLoggerLevel.WARNING, message);
        }

        public void warning(String message, Exception e)
        {
            log(SimpleLoggerLevel.WARNING, message, e);
        }

        public void error(String message, Exception e)
        {
            log(SimpleLoggerLevel.ERROR, message, e);
        }

        public void error(Exception e)
        {
            log(SimpleLoggerLevel.ERROR, "", e);
        }

        public void log(SimpleLoggerLevel level, string message)
        {
            log(level, message, null);
        }

        public void log(SimpleLoggerLevel level, string message, Exception exception)
        {
            if ((this.level.HasValue) && (this.level.Value.CompareTo(level) <= 0))
            {
                SimpleLogRecord logRecord = new SimpleLogRecord(name, level, message, exception);
                flushCount++;
                if (flushCount == flushInterval)
                    flushCount = 0;
                foreach (SimpleLoggerAppender appender in appenders)
                {
                    appender.append(logRecord);
                    if (flushCount == 0)
                        appender.flush();
                }
            }
        }
    }
}
